using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace EventBehaviorTree
{
    [Serializable]
    public abstract class Container<WorkMode> : EventNode
    {
        protected List<EventNode> _subNodes;
        protected IEnumerator _worker;
        protected Func<bool> Condition = delegate { return false; };
        protected WorkMode _workMode;
        protected int _stepCount = 0;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="isStopInstantly">Stop sub nodes coroutines instantly once the task is done.</param>
        /// <param name="isStopSimultaneously">Stop sub nodes once success.</param>
        public Container() { _subNodes = new List<EventNode>(); }

        /// <summary>
        /// Add node to the list and set the key for subNode.
        /// </summary>
        /// <param name="subNode"></param>
        public void AddSubNode(params EventNode[] subNodes)
        {
            foreach (var subNode in subNodes)
            {
                _subNodes.Add(subNode);
                subNode.SetKey(Key + "." + _stepCount);
                _stepCount++;
                subNode.SetReceiver(NodeEvent);
            }
        }

        public override void SetCoroutineStarter(MonoBehaviour coroutineStarter)
        {
            _coroutineStarter = coroutineStarter;
            foreach (EventNode subNode in _subNodes) { subNode.SetCoroutineStarter(coroutineStarter); }
        }

        protected virtual IEnumerator Worker()
        {
            switch (_workMode)
            {
                case ContainerMode.Async:
                    SeniorNodeEvent(NodeMessage.Success);
                    break;
                default:
                    break;
            }
            yield return new WaitUntil(Condition);
            switch (_workMode)
            {
                case ContainerMode.Busy:
                    SeniorNodeEvent(NodeMessage.Success);
                    break;
                default:
                    break;
            }
            ResetWorker();
        }

        protected void ResetWorker()
        {
            if (_worker != null)
            {
                _coroutineStarter.StopCoroutine(_worker);
                _worker = null;
            }
            _worker = Worker();
        }

        /// <summary>
        /// Seletor: just one working node; Sequencer: all nodes are working.
        /// </summary>
        protected void StopAllSubNodes()
        {
            foreach (EventNode subNode in _subNodes) subNode.NodeEvent(NodeMessage.COMMAND_Stop);
        }
    }
}